iT邦幫忙

2021 iThome 鐵人賽

DAY 10
1
自我挑戰組

馬克的軟體架構小筆記系列 第 10

30-10 之Presentation Layer - MVVM ( Model-View-ViewModel )

  • 分享至 

  • xImage
  •  

這個東東主要的概念來自 Martin Fowler 所寫的 《 Presentation Model 》這篇文章,MVVM 基本上算是 PM ( Presentation Model ) 的變體,不過當初 PM 主要是以 GUI 為主撰寫,不太確定是否與 web 打架…

( 小備註: 這個人的 Blog 可以說是通往軟體架構師必看之 Blog )

接下來談談 MVVM 的三個主題

  • Model : 基本上就是資料源,API 或是資料庫都有可能。
  • ViewModel : 會從 model 抓取 view 所需要的資料,並且維護 state。
  • View : 純 UI,以 web 來說就是純 html。

https://ithelp.ithome.com.tw/upload/images/20210925/20089358etPNL6fXG0.png
圖片來源: educative-Acing the JavaScript Design Patterns Interview

認真說,我第一眼看到就覺得,viewModel 的功能怎麼和 MVP 的 presenter 有點像呢 ? 這裡有幾個重點和 MVP 與 MVC 不太一樣。

  • view 與 model 本身有 data binding,由 view model 這實作,
  • MVP 的 view 有一些畫面邏輯,而 MVVM 的 view 就是純畫面例如 web html。

範例

這裡的範例我直接從 educative 內的範例來抓下重點部份來說明。

  • Model : 這裡主要有使用 pub/sub 模式,當 model 有什麼變化時,會去通知 observer ( Ex. setNameValue 這裡面 ),這裡沒有用 EventEmitter (nodejs) 主要的原因在於,這個範例是前端用的。
  • ViewModel : 這個範例中,它幾乎是實作了 date-binding 也就是將 view 與 model 進行雙向綁定,當 model 資料有變動就會去更新 view,反之也是。
  • View : 就是純 html 了。
// Model
class Model {
  constructor () {
    this.model = { name: 'Mark' }
    this.observers = []
  }

  subscribe (observer) {
    this.observers.push(observer)
  }

  notifyObservers (attrName, newVal) {
    for (let i = 0; i < this.observers.length; i++) {
      this.observers[i](attrName, newVal)
    }
  }

  getCurrentName (nameKey) {
    return this.model[nameKey]
  }

  setNameValue (nameKey, value) {
    this.model[nameKey] = value
    this.notifyObservers(nameKey, value)
  }
}

// ViewModel

class ViewModel {
  constructor (model) {
    this.bind = function (viewElement, modelElement) {
      // 將 view element 與 model element 綁在一起。
      viewElement.value = model.getCurrentName(modelElement)
      // 當 view 有什麼事件時,會執行 model 的事件
      viewElement.addEventListener('input', () => {
        model.setNameValue(viewElement.name, viewElement.value)
      })
      // 當 model 發生變化時,會自動修改 view 的值
      model.subscribe((attrName, newValue) => {
        document.getElementsByName(attrName).forEach((elem) => {
          elem.value = newValue.toUpperCase()
        })
      })
    }
  }
}

// View 純 HTML
<input type="text" name = "name" id="name">

// 使用時
const nameInput = document.getElementById('name');
const model = new Model()
const viewModel = new ViewModel(model);
viewModel.bind(nameInput, 'name');

小總結

這個知識點可以用來解釋什麼現象

我自已的看法 MVVM 有點感覺是給純前端使用,你可以想成幾乎每什麼商業邏輯,單純的重點就在於 :

『 畫面 』與 『 資料 』的 『 綁定 』

有點像是之前聽過的 vue 的『 雙向綁定 』,這樣感覺 vue 應該是以 MVVM 為基礎理念來設計,但是上網查了一下,知乎有一篇在討論這個主題,有興趣的看一下。不過先說好我是後端,對前端的事情不太熟喔

知乎 - 为什么尤雨溪尤大说VUE没有完全遵循MVVM?

這個知識點可以和以前的什麼知識連結呢 ?

我的腦袋就是迸出了以下幾個詞 :

  • 雙向綁定
  • 單向綁定

這兩個東西前端應該是非常的常聽到,我這裡比較想知道的是,這兩個的優缺比較,然後一下我覺得這篇文章還不錯,可以參考看看,不過我不是前端,不一定專業。

前端三大框架:資料繫結與資料流

我要如何運用這個知識點 ?

我突然想到,以後端的世界來說,很常會將資料存在 cache 與 db 中,這個應該有辦法進行『 雙向綁定的概念 』這樣當資料庫更新時,自動也會更新 cache 的資料。

參考資料


上一篇
30-9 之Presentation Layer - MVP ( Model-View-Presenter )
下一篇
30-11 之Domain Layer - Transaction Script
系列文
馬克的軟體架構小筆記29
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
pjchender
iT邦新手 3 級 ‧ 2021-09-27 08:52:58

我的感覺和馬克大找到的文章相似,雙向綁定用起來輕鬆方便,多數情境用起來都很舒服,但在比較複雜的情境會相對不好 Trace 資料/畫面變化的原因;相對的,單向綁定寫起來程式碼會多一點,但可以確定畫面的改變一定是因為資料改變導致的。

我要留言

立即登入留言